﻿using System.Linq;
using System.Windows.Forms;

namespace Borg.Framework
{
    public class PlugCheckedListBox : CheckedListBox, IAttachable
    {
        public PlugCheckedListBox()
        {
            Enabled = false;
        }

        public void Attach(SlotInfo slot)
        {
            Slot = slot;

            slot.Registered += Registered;
            slot.Deregistered += Deregistered;

            slot.Plugged += Plugged;
            slot.Unplugged += Unplugged;
            
            Items.Clear();

            foreach (var plugType in Slot.RegisteredPlugTypeInfos)
                Items.Add(plugType, plugType);

            Enabled = true;
        }

        public void Deregistered(object sender, RegisterEventArgs args)
        {
            Items.Remove(args.PlugTypeInfo);
        }

        public void Detach()
        {
            Enabled = false;
            
            Slot.Registered -= Registered;
            Slot.Deregistered -= Deregistered;
            
            Slot.Plugged -= Plugged;
            Slot.Unplugged -= Unplugged;
            
            Items.Clear();
            Slot = null;
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);

            if (Slot != null)
                Detach();
        }

        protected override void OnItemCheck(ItemCheckEventArgs args)
        {
            base.OnItemCheck(args);

            if (noUpdate)
                return;

            noUpdate = true;

            var kvPair = Items[args.Index];
            var key = (PlugTypeInfo)kvPair.Key;

            switch (args.NewValue)
            {
                case CheckState.Unchecked:
                    foreach (var plug in Slot.PluggedPlugInfos.
                        Where(plug => plug.PlugTypeInfo == key))
                    {
                        plug.Unplug(Slot);
                        break;
                    }
                    break;

                case CheckState.Checked:
                    key.Plug(Slot);
                    break;
            }

            noUpdate = false;
        }

        public void Plugged(object sender, PlugEventArgs args)
        {
            noUpdate = true;
            SetItemChecked(Items.IndexOf(args.PlugInfo.PlugTypeInfo), true);
            noUpdate = false;
        }

        public void Registered(object sender, RegisterEventArgs args)
        {
            Items.Add(args.PlugTypeInfo, args.PlugTypeInfo);
        }

        public void Unplugged(object sender, PlugEventArgs args)
        {
            noUpdate = true;
            SetItemChecked(Items.IndexOf(args.PlugInfo.PlugTypeInfo), false);
            noUpdate = false;
        }

        public SlotInfo Slot { get; private set; }
    }
}

